﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="With_AttachedObjectCollection.cs" company="JDML Consulting Ltd.">
//   Copyright 2011 Photon Project - http://photon.codeplex.com
// </copyright>
// <summary>
//   Defines the With_AttachedObjectCollection type.
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace Photon.Windows
{
    using System.Windows;
    using Infrastructure;
    using Microsoft.VisualStudio.TestTools.UnitTesting;

    [TestClass]
    public class With_AttachedObjectCollection
    {
        public class TestAssociatedObject : DependencyObject
        {
        }
        
        public class TestAttachedObject : AttachedObject<TestAssociatedObject>
        {
            public new TestAssociatedObject AssociatedObject
            {
                get { return base.AssociatedObject; }
            }
        }

        [TestMethod]
        public void When_created_should_not_be_attached()
        {
            var attachedCollection = new AttachedCollection<TestAttachedObject>();
            Assert.IsNull(attachedCollection.AsAttached().AssociatedObject);
        }

        [TestMethod]
        public void When_item_is_added_to_an_unattached_collection_should_not_attach_item()
        {
            var attachedCollection = new AttachedCollection<TestAttachedObject>();
            attachedCollection.Add(new TestAttachedObject());
            Assert.IsNull(attachedCollection[0].AsAttached().AssociatedObject);
        }

        [TestMethod]
        public void When_item_is_added_to_an_attached_collection_should_attach_item()
        {
            var testAssociatedObject = new TestAssociatedObject();

            var attachedCollection = new AttachedCollection<TestAttachedObject>();
            attachedCollection.AsAttached().Attach(testAssociatedObject);
            attachedCollection.Add(new TestAttachedObject());
            Assert.AreEqual(testAssociatedObject, attachedCollection[0].AssociatedObject);
        }

        [TestMethod]
        public void When_collection_containing_items_is_attached_should_attach_items()
        {
            var testAssociatedObject = new TestAssociatedObject();

            var attachedCollection = new AttachedCollection<TestAttachedObject>();
            attachedCollection.Add(new TestAttachedObject());
            attachedCollection.AsAttached().Attach(testAssociatedObject);

            Assert.AreEqual(testAssociatedObject, attachedCollection[0].AssociatedObject);
        }

        [TestMethod]
        public void When_collection_is_detached_should_detach_all_items()
        {
            var testAssociatedObject = new TestAssociatedObject();

            var attachedCollection = new AttachedCollection<TestAttachedObject>();
            attachedCollection.AsAttached().Attach(testAssociatedObject);
            attachedCollection.Add(new TestAttachedObject());
            Assert.AreEqual(testAssociatedObject, attachedCollection[0].AssociatedObject);
            attachedCollection.AsAttached().Detach();
            Assert.IsNull(attachedCollection[0].AssociatedObject);
        }

        [TestMethod]
        public void When_item_is_removed_to_should_detach()
        {
            var testAssociatedObject = new TestAssociatedObject();

            var attachedCollection = new AttachedCollection<TestAttachedObject>();
            attachedCollection.AsAttached().Attach(testAssociatedObject);
            var testAttachedObject = new TestAttachedObject();
            attachedCollection.Add(testAttachedObject);
            Assert.AreEqual(testAssociatedObject, testAttachedObject.AssociatedObject);
            attachedCollection.Remove(testAttachedObject);
            Assert.IsNull(testAttachedObject.AssociatedObject);
        }

        [TestMethod]
        public void When_item_is_duplicated_should_detach_when_all_occurances_have_been_removed()
        {
            var testAssociatedObject = new TestAssociatedObject();
            var attachedCollection = new AttachedCollection<TestAttachedObject>();
            attachedCollection.AsAttached().Attach(testAssociatedObject);
            
            //  add items
            var testAttachedObject = new TestAttachedObject();
            attachedCollection.Add(testAttachedObject);
            attachedCollection.Add(testAttachedObject);
            attachedCollection.Add(testAttachedObject);
            Assert.AreEqual(testAssociatedObject, testAttachedObject.AssociatedObject);
            
            //  remove, should only detach on last removal
            attachedCollection.Remove(testAttachedObject);
            Assert.AreEqual(testAssociatedObject, testAttachedObject.AssociatedObject);
            attachedCollection.Remove(testAttachedObject);
            Assert.AreEqual(testAssociatedObject, testAttachedObject.AssociatedObject);
            attachedCollection.Remove(testAttachedObject);
            Assert.IsNull(testAttachedObject.AsAttached().AssociatedObject);
        }

        [TestMethod]
        public void When_cleared_should_detach()
        {
            var testAssociatedObject = new TestAssociatedObject();

            var attachedCollection = new AttachedCollection<TestAttachedObject>();
            attachedCollection.AsAttached().Attach(testAssociatedObject);

            // add items
            var testAttachedObject1 = new TestAttachedObject();
            var testAttachedObject2 = new TestAttachedObject();
            attachedCollection.Add(testAttachedObject1);
            attachedCollection.Add(testAttachedObject2);
            Assert.AreEqual(testAssociatedObject, testAttachedObject1.AssociatedObject);
            Assert.AreEqual(testAssociatedObject, testAttachedObject2.AssociatedObject);

            // clear and verify detached
            attachedCollection.Clear();
            Assert.IsNull(testAttachedObject1.AssociatedObject);
            Assert.IsNull(testAttachedObject2.AssociatedObject);
        }
    }
}
